const http = require("http");
const path = require("path");
const url = require("url");
const fs = require("fs").promises;
const { createReadStream } = require("fs");
const mime = require("mime");
const ejs = require("ejs");
const { promisify } = require("util");

function mergeConfig(config) {
  return {
    port: 1234, // 默认端口
    directory: process.cwd(), // 默认目录
    ...config,
  };
}

class Server {
  constructor(config) {
    this.config = mergeConfig(config);
    console.log(this.config);
  }

  start() {
    let server = http.createServer(this.serveHandle.bind(this));
    server.listen(this.config.port, () => {
      console.log("服务端已经启动");
    });
  }

  async serveHandle(req, res) {
    let { pathname } = url.parse(req.url, true);
    pathname = decodeURIComponent(pathname);
    let absPath = path.join(this.config.directory, pathname);
    try {
      let statObj = await fs.stat(absPath);
      if (statObj.isFile()) {
        this.fileHandle(req, res, absPath);
      } else {
        let dirs = await fs.readdir(absPath);
        dirs = dirs.map((item) => {
          return {
            path: path.join(pathname, item),
            dirs: item,
          };
        });
        let renderFile = promisify(ejs.renderFile);
        let parentpath = path.dirname(pathname);
        let ret = await renderFile(path.resolve(__dirname, "template.ejs"), {
          arr: dirs, // 目录数组
          parent: pathname === "/" ? false : true, // 是否有父目录
          parentpath, // 父目录路径
          title: path.basename(absPath), // 标题
        });
        res.statusCode = 200;
        res.setHeader("Content-Type", "text/html;charset=utf-8");
        res.end(ret);
      }
    } catch (error) {
      this.errorHandle(req, res, error);
    }
  }

  errorHandle(req, res, error) {
    res.statusCode = 404;
    res.setHeader("Content-Type", "text/html;charset=utf-8");
    res.end("404 Not Found\n");
  }

  fileHandle(req, res, absPath) {
    res.statusCode = 200;
    res.setHeader("Content-Type", mime.getType(absPath) + ";charset=utf-8");
    createReadStream(absPath).pipe(res);
  }
}

module.exports = Server;
